package com.zd.Controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zd.entity.User;
import com.zd.entity.ValueObject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/quick21")
    @ResponseBody
    public void save21(String username, MultipartFile upload) throws IOException {//这里的参数名称要与form表单中的name对应
        String filename = upload.getOriginalFilename();//获得文件名称
        //保存文件
        upload.transferTo(new File("C:\\upload\\"+filename));
    }

    @RequestMapping(value = "/quick20")
    @ResponseBody
    public void save20(@CookieValue(value = "JESSIONID") String jsessionId){
        System.out.println(jsessionId);//获取请求头中的信息
    }

    @RequestMapping(value = "/quick19")
    @ResponseBody
    public void save19(@RequestHeader(value = "User-Agent") String use_agent){
        System.out.println(use_agent);//获取请求头中的信息
    }

    /*自定义类型转换器
         SpringMVC默认已经提供了一些常用的类型转换器，例如：客户端提交的字符串（客户端都是String类型的）转化成int型
         然而有些需要我们自定义转换器：例如：日期的转换：当我们在前端提交的url地址是：localhost:8080/Spring_MVC_war_exploded/user/quick18?date=2018/12/21时可以进行日期的转换（SpringMVC提供了对应的转换器了）。
         然而当我们在在前端提交的url地址是：localhost:8080/Spring_MVC_war_exploded/user/quick18?date=2018-12-21的时候就不能正常的转化了
         自定义类型转换器的开发步骤：
         1.自定义转换器类实现Converter接口
         2.在配置文件中声明转换器
         3.在<mvc:annotation-driven>中引用转换器
    */
    @RequestMapping(value = "/quick18")
    @ResponseBody
    public void save18(Date date){
        System.out.println(date);
    }


    //假设这里给的请求地址是http://locahost:8080/Spring_MVC_war_exploded/quick17/cengdong    这里可以看看我自己写的博客
    @RequestMapping(value = "/quick17/{name}")
    @ResponseBody
    public void save17(@PathVariable(value = "name") String username){
        System.out.println(username);//这是输出chengdong
    }

    /*
      参数绑定注解@requestParam
      当请求的参数的名称与Controller的业务方法的参数名称不一致时，就需要@requestParam注解显示的绑定
      注解@requestParam还有如下参数可以使用：
       value:与请求的参数名称一致
       required:表示请求是否必须包括参数（也就是上面Value中写的那个参数），默认是true：表示必须写，不写的话就会报错  可以改为false：表示请求中没有这个参数的话就提交的是null
       defaultValue:表示如果上面没有写参数的话就使用defaultValue中的参数
    */
   @RequestMapping(value = "/quick16")
   @ResponseBody
   public void save16(@RequestParam(value = "name",required = false,defaultValue = "itcate") String username){//value="name"代表请求中的参数名声是name
       System.out.println(username);
   }

    //从前端页面获取集合类型的参数:第二种方式：当使用ajax提交时，可以指定contentType为json形式，那么在方法参数位置使用@RequestBody可以直接接收集合数据，而无需使用POJO进行包装
    @RequestMapping(value = "/quick15")
    @ResponseBody//必须写这个代表不进行页面跳转
    public void save15(@RequestBody List<User> userList){//@RequestBody代表把请求体中的内容直接封到List中
        System.out.println(userList);
    }

    //从前端页面获取集合类型的参数:业务方法中的形参是一个ValueObject对象，这个类里面有一个叫userList的属性名，所以我们前端传过来的数据也要是一个集合而且名称也要一样
    @RequestMapping(value = "/quick14")
    @ResponseBody//必须写这个代表不进行页面跳转
    public void save14(ValueObject valueObject){//前端传过来的参数要与这个类中的属性名称一样
        System.out.println(valueObject);
    }

    //从前端页面获取数组类型的参数:业务方法中的数组名称要与请求参数的name一致，参数值就会自动映射匹配
    @RequestMapping(value = "/quick13")
    @ResponseBody//必须写这个代表不进行页面跳转
    public void save13(String[] usernames){
        System.out.println(Arrays.asList(usernames));
    }

    //从前端页面获取POJO类型的参数：也就是把前端页面传来的username和age属性封装到User对象中去（这里要保证前端的属性名name要与User这个类中的属性名一样，这样SpringMVC就会自动通过User这个类中的set方法进行封装了）
    @RequestMapping(value = "/quick12")
    @ResponseBody//必须写这个代表不进行页面跳转
    public void save12(User user){
        System.out.println(user);
    }

    //从前端页面获取基本类型的参数
    @RequestMapping(value = "/quick11")
    @ResponseBody//必须写这个代表不进行页面跳转
    public void save11(String username,int age){
        System.out.println(username+": "+age);
    }

    //数据响应方式之回写数据-返回一个对象或者集合
    //期望SpringMVC自动将对象转换成jason字符串格式（所以这里需要配置处理器映射器）
    @RequestMapping(value = "/quick10")
    @ResponseBody
    public User save10() throws IOException {
        User user = new User();
        user.setUsername("lisa");
        user.setAge("18");

        return user;
    }

    //数据响应方式之回写数据-返回json格式的字符串-通过json的转化工具将对象转换成json格式字符串然后再返回（这里要导坐标）
    @RequestMapping(value = "/quick9")
    @ResponseBody
    public String save9() throws IOException {
        User user = new User();
        user.setUsername("lisa");
        user.setAge("18");
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(user);
        return json;
    }

    //数据响应方式之回写数据-返回json格式的字符串
    @RequestMapping(value = "/quick8")
    @ResponseBody
    public String save8() throws IOException {
        return "{\"Username\":\"Zhangshan\",\"age\":18}";//引号需要转译
    }

    //数据响应方式之回写数据-直接返回字符串的方式
    @RequestMapping(value = "/quick7",produces = "text/html;charset=UTF-8")//produces:解决回写数据乱码问题
    @ResponseBody//告知SpringMvc框架不进行跳转，而是回写数据
    public String save7() throws IOException {
        return "回写数据-直接返回字符串的方式";
    }

    //数据响应方式之回写数据
    @RequestMapping(value = "/quick6")
    public void save6(HttpServletResponse response) throws IOException {
        response.getWriter().print("回写数据");
    }

    //这种方式不常用
    @RequestMapping(value = "/quick5")
    public String save5(HttpServletRequest httpServletRequest){  //springMvc对这个方法的参数，可以进行相应的注入
        httpServletRequest.setAttribute("username","小康");
        return "Success";
    }

    //返回字符串类型和Model进行结合，从而达到返回ModelAndView一样的效果
    @RequestMapping(value = "/quick4")
    public String save4(Model model){  //springMvc对这个方法的参数，可以进行相应的注入
        model.addAttribute("username","小李");
        return "Success";
    }

    //返回ModelAndView对象
    @RequestMapping(value = "/quick3")
    public ModelAndView save3(ModelAndView modelAndView){  //springMvc对这个方法的参数，可以进行相应的注入
        modelAndView.addObject("username","小红");
        //设置视图名称
        modelAndView.setViewName("Success");
        return modelAndView;
    }

    //返回ModelAndView对象
    @RequestMapping(value = "/quick2")
    public ModelAndView save2(){
        System.out.println("Controller save running...");
        /*
           Model:模型：作用是封装数据
           View: 视图：作用是展示数据
        */
        ModelAndView modelAndView = new ModelAndView();
        //设置模型数据：设置的数据类型为键值对，然后在页面中我们就可以通过El表达式得到这个值然后显示
        modelAndView.addObject("username","小明");
        //设置视图名称
        modelAndView.setViewName("Success");
        return modelAndView;
    }


    //返回字符串的形式
    @RequestMapping(value = "/quick",method = RequestMethod.GET,params = {"username"})
    public String save(){
        System.out.println("Controller save running...");
        return "Success"; //配置内部资源视图解析器 添加前缀和后缀，这样就只用写Success
       //return "/jsp/Success.jsp";//返回要跳转的视图，也就是页面  在视图解析器中的底层默认使用的是Forward（转发：地址不发生改变）， 我们也可以改为rediect:Success.jsp,重定向的方式进行页面跳转
    }
}

//@RequestMapping
//作用：用于建立请求URL和处理请求方法之间的对应关系
//位置： 1.类上：请求URL的第一级访问目录，此处不写的话，相当于应用的根目录
         //2.方法上：请求URL的第二级访问目录，与类上的@RequestMapping标注的以及目录一起组成访问虚拟路径
//属性：valu：用于请求的URL，他和Path的作用是一样的
     //method：用于指定请求的方式。
     //params：用于指定限制请求参数的条件，他支持简单的表达式，要求请求的Key和Value必须和配置一模一样
    //列如：params={“accountment”}  表示请求的参数必须有accountment  params={“moeny!100”},表示请求的参数中moeny不能是100